package com.greensam.pixelengine.facade.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.greensam.pixelengine.event.pixel.PixelEvent;
import com.greensam.pixelengine.event.pixel.PixelEventBus;
import com.greensam.pixelengine.event.pixel.PixelEventType;
import com.greensam.pixelengine.manager.auth.StpKit;
import com.greensam.pixelengine.pojo.base.DeleteRequest;
import com.greensam.pixelengine.pojo.base.PaginationResponse;
import com.greensam.pixelengine.constant.BaseConstant;
import com.greensam.pixelengine.constant.UserConstant;
import com.greensam.pixelengine.pojo.entity.RolePo;
import com.greensam.pixelengine.pojo.vo.role.response.RoleVo;
import com.greensam.pixelengine.pojo.vo.user.request.UserPageRequest;
import com.greensam.pixelengine.pojo.vo.user.request.UserSaveRequest;
import com.greensam.pixelengine.pojo.vo.user.request.UserLoginRequest;
import com.greensam.pixelengine.pojo.vo.user.request.UserRegisterRequest;
import com.greensam.pixelengine.pojo.emuns.ErrorCodeEnum;
import com.greensam.pixelengine.pojo.emuns.StatusEnum;
import com.greensam.pixelengine.exception.BusinessException;
import com.greensam.pixelengine.exception.ResultCode;
import com.greensam.pixelengine.facade.UserFacadeService;
import com.greensam.pixelengine.pojo.entity.UserPo;
import com.greensam.pixelengine.pojo.vo.user.response.LoginUserVo;
import com.greensam.pixelengine.pojo.vo.user.response.UserVo;
import com.greensam.pixelengine.service.RoleDataService;
import com.greensam.pixelengine.service.UserDataService;
import com.greensam.pixelengine.utils.DataUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.*;

/**
 * @author Macro_Ray
 * @since 2025/6/17 11:48
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserFacadeServiceImpl implements UserFacadeService {

    private final PixelEventBus pixelEventBus;
    private final UserDataService userDataService;
    private final RoleDataService roleDataService;

    @Override
    public Long userRegister(UserRegisterRequest request) {
        // 1. 参数校验
        validation(request);
        // 2. 检查账号是否已存在
        userDataService.getUserByAccount(request.getAccount()).ifPresent(u -> {
            throw new BusinessException(ErrorCodeEnum.UserIsExist);
        });
        // 3. 密码加密
        String encryptPassword = getEncryptPassword(request.getPassword());
        // 4. 插入数据
        // 初始用户名 Greensam + 随机五位数
        String name = BaseConstant.LOGO + (int) ((Math.random() * 9 + 1) * 10000);
        UserPo userPo = new UserPo()
                .setAccount(request.getAccount())
                .setPassword(encryptPassword)
                .setName(name)
                .setStatus(StatusEnum.Approved);
        UserPo dbUserPo = userDataService.save(userPo);
        if (Objects.isNull(dbUserPo)) {
            throw new BusinessException(ErrorCodeEnum.OperationDataError);
        }
        Long userId = dbUserPo.getId();
        dbUserPo.setCreateBy(userId);
        dbUserPo.setUpdateBy(userId);
        userDataService.save(dbUserPo);
        log.info("用户注册成功，用户ID：{}", userId);
        return userId;
    }

    @Override
    public LoginUserVo userLogin(UserLoginRequest param, HttpServletRequest request) {
        // 1. 校验参数
        if (StrUtil.hasBlank(param.getAccount(), param.getPassword())) {
            throw new BusinessException(ErrorCodeEnum.ParamValidError, "参数不可为空");
        }
        // 2. 对用户传递的密码进行加密
        String encryptPassword = getEncryptPassword(param.getPassword());
        // 3. 查询数据库中用户是否存在
        UserPo userPo = userDataService.getUserByAccount(param.getAccount())
                .orElseThrow(() -> new BusinessException(ErrorCodeEnum.UserLoginError));
        if (!userPo.getPassword().equals(encryptPassword)) {
            log.error("user password not match");
            throw new BusinessException(ErrorCodeEnum.UserLoginError);
        }
        // 4. 保存用户登陆状态
        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, userPo);
        // 5. 记录用户登录态到 Sa-token，便于空间鉴权使用。用户信息与 SpringSession 中的信息过期时间一直
        StpKit.SPACE.login(userPo.getId());
        StpKit.SPACE.getSession().set(UserConstant.USER_LOGIN_STATE, userPo);

        log.info("用户登陆成功，用户ID: {}", userPo.getId());
        LoginUserVo vo = convertUserLoginVo(userPo);
        pixelEventBus.publish(new PixelEvent(PixelEventType.USER_LOGIN, vo));
        return vo;
    }

    public UserVo convertUserVo(UserPo userPo) {
        if (Objects.isNull(userPo)) {
            return null;
        }
        return BeanUtil.copyProperties(userPo, UserVo.class);
    }

    @Override
    public List<UserVo> getUsersByRoleId(Long id) {
        if (Objects.isNull(id)) {
            return Collections.emptyList();
        }
        List<UserPo> userPoList = userDataService.getUsersByRoleId(id);
        return userPoList.stream().map(this::convertUserVo).toList();
    }

    @Override
    public UserVo getUserVo(Long id) {
        UserPo userPo = userDataService.getUserById(id)
                .orElseThrow(() -> new BusinessException(ErrorCodeEnum.UserIsNotExist));
        return convertUserVo(userPo);
    }

    @Override
    public Boolean deleteUser(DeleteRequest request, Long userId) {
        userDataService.getUserById(request.getId()).ifPresent(userPo -> {
            if (!userPo.getId().equals(userId) && !roleDataService.isAdmin(userId)) {
                throw new BusinessException(ResultCode.NO_AUTH_ERROR, "仅本人或管理员可以操作");
            }
            userPo.setUpdateBy(userId);
            userPo.setDelete(Boolean.TRUE);
            userPo.setStatus(StatusEnum.Deleted);
            userDataService.save(userPo);
            log.info("用户 {} 删除成功", userPo.getId());
        });
        return Boolean.TRUE;
    }

    @Override
    public PaginationResponse<UserVo> pageUser(UserPageRequest request) {
        PaginationResponse<UserPo> pageResponse = userDataService.pageUser(request);
        if (pageResponse.isEmpty()) {
            return PaginationResponse.empty(request.getPageNum(), request.getPageSize());
        }
        return pageResponse.map(this::convertUserVo);
    }

    @Override
    public UserPo getLoginUser(HttpServletRequest request) {
        // 判断是否已经登陆
        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        UserPo currentUser = (UserPo) userObj;
        if (Objects.isNull(currentUser) || Objects.isNull(currentUser.getId())) {
            throw new BusinessException(ResultCode.NOT_LOGIN_ERROR);
        }
        // 从数据库查询
        Long userId = currentUser.getId();
        Optional<UserPo> userPo = userDataService.getUserById(userId);
        if (userPo.isEmpty()) {
            throw new BusinessException(ResultCode.NOT_LOGIN_ERROR);
        }
        currentUser = userPo.get();
        log.info("获取登陆用户: {}", currentUser.getId());
        return currentUser;
    }

    @Override
    public LoginUserVo getLoginUserVo(HttpServletRequest request) {
        UserPo loginUserPo = getLoginUser(request);
        if (Objects.isNull(loginUserPo)) {
            return null;
        }
        LoginUserVo loginUserVo = convertUserLoginVo(loginUserPo);

        List<RolePo> rolePos = userDataService.listRoleByUserId(loginUserPo.getId());
        List<RoleVo> roleVos = new ArrayList<>();
        if (rolePos != null) {
            roleVos = rolePos.stream()
                    .map(rolePo -> BeanUtil.copyProperties(rolePo, RoleVo.class))
                    .toList();
        }
        loginUserVo.setRoles(roleVos);
        log.debug("获取登录用户信息：{}", loginUserVo);
        return loginUserVo;
    }

    @Override
    public Boolean userLogout(HttpServletRequest request) {
        // 判断是否已经登陆
        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        if (Objects.isNull(userObj)) {
            throw new BusinessException(ResultCode.OPERATION_ERROR, "未登录");
        }
        log.debug("用户登出，用户ID：{}", ((UserPo) userObj).getId());
        // 移除登录态建
        request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
        return Boolean.TRUE;
    }

    @Override
    public UserPo saveUser(UserSaveRequest request, Long userId) {
        if (Objects.isNull(request)) {
            throw new BusinessException(ErrorCodeEnum.ParamValidError);
        }
        UserPo userPo;
        if (Objects.nonNull(request.getId())) {
            // 修改用户
            userPo = userDataService.getUserById(request.getId())
                    .orElseThrow(() -> new BusinessException(ErrorCodeEnum.UserIsNotExist));
            DataUtils.setIfNotNull(request.getName(), userPo::setName);
            DataUtils.setIfNotNull(request.getGender(), userPo::setGender);
            DataUtils.setIfNotNull(request.getEmail(), userPo::setEmail);
            DataUtils.setIfNotNull(request.getPhone(), userPo::setPhone);
            DataUtils.setIfNotNull(request.getAvatar(), userPo::setAvatar);
            DataUtils.setIfNotNull(request.getProfile(), userPo::setProfile);
        } else {
            // 新增用户
            userPo = BeanUtil.copyProperties(request, UserPo.class);
            userPo.setCreateBy(userId);
            userPo.setPassword(getEncryptPassword(UserConstant.DEFAULT_PASSWORD));
            userPo.setStatus(StatusEnum.Approved);
        }
        userPo.setUpdateBy(userId);
        UserPo save = userDataService.save(userPo);
        log.info("保存用户成功：{}", save);
        return save;
    }

    @Override
    public Optional<UserPo> getUserById(Long id) {
        return userDataService.getUserById(id);
    }

    /**
     * 检验参数
     *
     * @param request 参数
     * @author Macro_Ray
     * @since 2025/6/17
     */
    private static void validation(UserRegisterRequest request) {
        if (StrUtil.hasBlank(request.getAccount(), request.getPassword(), request.getCheckPassword())) {
            throw new BusinessException(ErrorCodeEnum.ParamValidError, "参数不可为空");
        }
        if (request.getAccount().length() < 4) {
            throw new BusinessException(ErrorCodeEnum.ParamValidError, "账号不可少于4位");
        }
        if (request.getPassword().length() < 6 || request.getCheckPassword().length() < 6) {
            throw new BusinessException(ErrorCodeEnum.ParamValidError, "密码不可少于6位");
        }
        if (!request.getPassword().equals(request.getCheckPassword())) {
            throw new BusinessException(ErrorCodeEnum.ParamValidError, "两次输入的密码不一致");
        }
    }

    /**
     * 用户实体转换为登录用户信息
     *
     * @param userPo 用户实体
     * @return LoginUserVo 登录用户信息
     * @author Macro_Ray
     * @since 2025/7/1
     */
    public LoginUserVo convertUserLoginVo(UserPo userPo) {
        if (Objects.isNull(userPo)) {
            return null;
        }
        return BeanUtil.copyProperties(userPo, LoginUserVo.class);
    }

    /**
     * 获取加密后的密码，md5加密
     *
     * @param password 密码
     * @return 加密后的密码
     * @author Macro_Ray
     * @since 2025/6/17
     */
    private String getEncryptPassword(String password) {
        String salt = "macro";
        return DigestUtils.md5DigestAsHex((salt + password).getBytes());
    }
}
